﻿using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Geometry;
using Microsoft.Graphics.Canvas.Svg;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.HumanInterfaceDevice;
using Windows.Devices.SerialCommunication;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace FASTControl
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>

    public sealed partial class HomePage : Page
    {
        public HomePage()
        {
            this.InitializeComponent();
            wave.Enqueue(new Vector2(0, (float)canvas.ActualWidth));
            // RegisterForDeviceWatcherEvents();
        }
        const ushort VID = 0x1A86;
        const ushort PID = 0xE6E1;
        DataReader dataReader;
        DataWriter dataWriter;
        private async Task<SerialDevice> getSerialDevice()
        {
            string selector = SerialDevice.GetDeviceSelectorFromUsbVidPid(VID, PID);
            var deviceInfo = await DeviceInformation.FindAllAsync(selector);
            if (deviceInfo.Count != 0)
            {
                SerialDevice device = await SerialDevice.FromIdAsync(deviceInfo[0].Id);
                if (device != null)
                {
                    dataReader = new DataReader(device.InputStream);
                    dataWriter = new DataWriter(device.OutputStream);
                    return device;
                }
            }
            return null;
        }
        private async Task<HidDevice> getHidDevice()
        {
            string selector = HidDevice.GetDeviceSelector(0xff01, 1, VID, PID);
            var deviceInfo = await DeviceInformation.FindAllAsync(selector);
            if (deviceInfo.Count != 0)
            {
                HidDevice device = await HidDevice.FromIdAsync(deviceInfo[0].Id, FileAccessMode.ReadWrite);
                if (device != null)
                {
                    return device;
                }
            }
            return null;
        }

        private async Task serialWrite(string input)
        {
            dataWriter.WriteString(input);
            await dataWriter.StoreAsync().AsTask(new CancellationTokenSource().Token);
        }
        private async Task<string> serialRead()
        {
            dataReader.InputStreamOptions = InputStreamOptions.Partial;
            Task<UInt32> loadAsyncTask = dataReader.LoadAsync(1024).AsTask(new CancellationTokenSource().Token);
            UInt32 bytesRead = await loadAsyncTask;
            return dataReader.ReadString(bytesRead);
        }
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            if (device == null)
            {
                device = await getHidDevice();
                if(device == null)
                    return;
            }
            byte outReportId = 13;
            HidOutputReport outReport = device.CreateOutputReport(outReportId);
            DataWriter writer = new DataWriter();
            writer.WriteByte(outReportId);
            writer.WriteBytes(new byte[19]);
            uint sendLength = await device.SendOutputReportAsync(outReport);
        }
        private TypedEventHandler<HidDevice, HidInputReportReceivedEventArgs> inputReportEventHandler;
        private void registerInputEvent(HidDevice device)
        {
            inputReportEventHandler = new TypedEventHandler<HidDevice, HidInputReportReceivedEventArgs>(this.InputReportReceived);
            device.InputReportReceived += inputReportEventHandler;
        }
        private void InputReportReceived(
            HidDevice sender,
            HidInputReportReceivedEventArgs args)
        {
            HidInputReport inputReport = args.Report;
            IBuffer buffer = inputReport.Data;
            DataReader dr = DataReader.FromBuffer(buffer);
            byte[] bytes = new byte[inputReport.Data.Length];
            dr.ReadBytes(bytes);

            String inputReportContent =
               System.Text.Encoding.ASCII.GetString(bytes);
        }

        public async void Invoke(Action action, Windows.UI.Core.CoreDispatcherPriority Priority = Windows.UI.Core.CoreDispatcherPriority.Normal)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Priority, () => { action(); });
        }
        HidDevice device;
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            device.InputReportReceived -= inputReportEventHandler;
            device.Dispose();
        }

        private async void Button_Click_2(object sender, RoutedEventArgs e)
        {
            byte reportId = 13;
            HidOutputReport outReport = device.CreateOutputReport(reportId);
            var dataWriter = new DataWriter();
            dataWriter.WriteByte(reportId);
            byte[] outport = new byte[19];
            dataWriter.WriteBytes(outport);
            outReport.Data = dataWriter.DetachBuffer();
            uint length = await device.SendOutputReportAsync(outReport);
        }
        private void RegisterForDeviceWatcherEvents()
        {
            var selector = HidDevice.GetDeviceSelector(1, 4, VID, PID);
            var deviceWatcher = DeviceInformation.CreateWatcher(selector);
            AddDeviceWatcher(deviceWatcher, selector);
            deviceWatcher.Start();
        }

        private void AddDeviceWatcher(DeviceWatcher deviceWatcher, String deviceSelector)
        {
            deviceWatcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>(this.OnDeviceAdded);
        }
        private async void OnDeviceAdded(DeviceWatcher sender, DeviceInformation deviceInformation)
        {
            await MainPage.Current.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                new DispatchedHandler(async () =>
                {
                    this.device = await HidDevice.FromIdAsync(deviceInformation.Id, FileAccessMode.ReadWrite);
                    bool a = device != null;

                }));
        }

        private void canvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            var width = (float)canvas.ActualWidth - 20;
            var height = (float)(canvas.ActualHeight) - 20;
            var midWidth = (float)(width * .5);
            var midHeight = (float)(height * .5);
            Color color = Colors.Gray;
            var canvasCommandList = new CanvasCommandList(sender);
            using (CanvasDrawingSession clds = canvasCommandList.CreateDrawingSession())
            {
                using (var cpb = new CanvasPathBuilder(clds))
                {
                    // Horizontal line
                    // 水平线
                    cpb.BeginFigure(new Vector2(0, midHeight));
                    cpb.AddLine(new Vector2(width, midHeight));
                    cpb.EndFigure(CanvasFigureLoop.Open);

                    // Horizontal line arrow
                    // 水平箭头
                    cpb.BeginFigure(new Vector2(width - 10, midHeight - 3));
                    cpb.AddLine(new Vector2(width, midHeight));
                    cpb.AddLine(new Vector2(width - 10, midHeight + 3));
                    cpb.EndFigure(CanvasFigureLoop.Open);

                    clds.DrawGeometry(CanvasGeometry.CreatePath(cpb), color, strokeWidth: 1);
                }
                using (var cpb = new CanvasPathBuilder(clds))
                {
                    // Vertical line
                    // 垂直线
                    cpb.BeginFigure(new Vector2(midWidth, 0));
                    cpb.AddLine(new Vector2(midWidth, height));
                    cpb.EndFigure(CanvasFigureLoop.Open);

                    // Vertical line arrow
                    cpb.BeginFigure(new Vector2(midWidth - 3, 10));
                    cpb.AddLine(new Vector2(midWidth, 0));
                    cpb.AddLine(new Vector2(midWidth + 3, 10));
                    cpb.EndFigure(CanvasFigureLoop.Open);

                    clds.DrawGeometry(CanvasGeometry.CreatePath(cpb), color, 1);
                }

                clds.DrawText("BingS", new Vector2(10, 10), Color.FromArgb(0xff, 11, 22, 33));
            }
            var offset = new Vector2((float)(x), (float)(y));
            // sender.Scale = new Vector3((float)scale, (float)scale, 3);
            // args.DrawingSession.DrawImage(canvasCommandList,offset);
            var ds = args.DrawingSession;

            float startAngle = 3.14f;
            float sweepAngle = (float)scale;
            CanvasStrokeStyle strokeStyle = new CanvasStrokeStyle()
            {
                StartCap = CanvasCapStyle.Round,
                EndCap = CanvasCapStyle.Triangle,
            };
            var centerPoint = new Vector2(150);
            var startPoint = Vector2.Transform(Vector2.UnitX, Matrix3x2.CreateRotation(startAngle)) * new Vector2(150,150);
            // Draw the arc.
            using (var builder = new CanvasPathBuilder(sender))
            {
                bezierStartPoint = wave.ElementAt(0);
                bezierStartPoint.X = 0;
                builder.BeginFigure(bezierStartPoint);
                int i = 0;
                foreach (var point in wave){
                    var endPoint = point;
                    endPoint.X = i;
                    i++;
                    //var bezierControl = bezierStartPoint + (endPoint - bezierStartPoint) / 2;
                    //builder.AddQuadraticBezier(bezierControl, endPoint);
                    builder.AddLine(endPoint);
                    bezierStartPoint = endPoint;
                }
                builder.EndFigure(CanvasFigureLoop.Open);
                using (var geometry = CanvasGeometry.CreatePath(builder))
                {
                    ds.DrawGeometry(geometry, Colors.Blue, 5, strokeStyle);
                }
            }            
        }
        Vector2 bezierStartPoint = new Vector2(0,0);
        Queue<Vector2> wave = new Queue<Vector2>();
        double x = 0,y = 0,scale = 1;
        double lx, ly;
        private void canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            PointerPoint point = e.GetCurrentPoint(canvas);
            lx = point.Position.X;
            ly = point.Position.Y;
        }

        private void canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            
            PointerPoint point = e.GetCurrentPoint(canvas);
            if (point.Properties.IsLeftButtonPressed)
            {
                if (wave.Count > canvas.ActualWidth)
                    wave.Dequeue();
                wave.Enqueue(new Vector2((float)(point.Position.Y)));
                canvas.Invalidate();
            }
        }

        private void canvas_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
        {
            PointerPoint point = e.GetCurrentPoint(canvas);
            scale += (point.Properties.MouseWheelDelta / 500.0);
        }
    }
}
